CH07-OpenCV 图像噪点

1. 图像阈值

1.1 简单阈值

灰度值阈值一般是 127

ret, bin = cv2.threshold(src, thresh, maxval, type)

参数 说明
src 进行处理的灰度值
thresh 设定的阈值
maxval 如果超过阈值,将大于阈值部分的像素点赋值为 maxval, 一般设为 255(逻辑 1)
type 进行二值化操作的类型
ret 判断二值化是否成功
bin 二值化后的输出图像

type:

  • cv2.THRESH_BINARY

    • 当图像中的像素点的灰度值大于阈值的时候,该像素点赋值为 maxval,否则就赋值为 0.
  • cv2.THRESH_BINARY_INV

    • 当图像中的像素点的灰度值大于阈值的时候,该像素点赋值为 0,否则就赋值为 maxval.
  • cv2.THRESH_TRUNC
    • 当图像中的像素值大于阈值时,将该像素值设为阈值(不是 maxval ),否则该像素值不变
  • cv2.THRESH_TOZERO
    • 大于阈值部分的像素点的灰度值保持不变,其余的像素点灰度值赋值为0
  • cv2.THRESH_TOZERO_INV
    • 大于阈值部分的像素点的灰度值赋值为0,其余的像素点灰度值保持不变
import cv2

img = cv2.imread('img/CH07-1.jpg')

# 获取图像属性
x = img.shape[0]
y = img.shape[1]
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 阈值操作
ret, thresh = cv2. threshold(grey, 127, 255, cv2.THRESH_BINARY)

# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', y, x)
cv2.imshow('img', thresh)

cv2.waitKey(0)
cv2.destroyAllWindows()

1.2 自适应阈值

使得同一幅图像上的不同区域一般会采用不同的阈值

在自适应阈值中,blockSize 必须满足大于 1,并且必须为奇数,否则会报错

dst = cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)

参数 说明
src 待处理的灰度值
maxValue 规定的像素值上限
adaptiveMethod 自适应方法:
cv2.ADAPTIVE_THRESH_MEAN_C : 领域内进行均值计算
cv2.ADAPTIVE_THRESH_GAUSSIAN_C : 领域像素点进行加权和
thresholdType 阈值类型:
1) cv2.THRESH_BINARY
2) cv2.THRESH_BINARY_INV
bloskSIze 规定每块自适应区域的大小
C 常数,最后的阈值等于指定正方形区域的均值减 C
dst 输出的图像
img = cv2.imread('img/CH07-1.jpg')

# 获取图像属性
x = img.shape[0]
y = img.shape[1]
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 阈值操作
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)

# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y/2), int(x/2))
cv2.imshow('img', thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

1.3 Otsu's二值化算法

该算法适合图像灰度直方图具有双峰的情况

灰度直方图中 x 轴对应 0~255 的灰度范围,y 轴为对应灰度值的点的数目

img = cv2.imread('img/CH07-1.jpg')

# 获取图像属性
x = img.shape[0]
y = img.shape[1]
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 阈值操作
# 用来手动设置阈值的参数 thresh 设置为 0,type 后面的参数需要加上cv2.THRESH_OTSU
ret, thresh = cv2.threshold(grey, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', y, x)
cv2.imshow('img', thresh)

cv2.waitKey(0)
cv2.destroyAllWindows()

2. 图像去噪

低通滤波(LPF) 用于去除噪声以及模糊图像; 高通滤波(HPF)用于找到图像的边缘

椒盐噪声-像一颗颗盐粒撒在一张图像上

高斯噪声-通常具有连续性,产生在同一条线上

2.1 2D 卷积

2.1.1 cv2.filter2D 函数

dst = cv2.filter2D(src, ddepth, kernel, anchor = None)

参数 说明
src 进行卷积的图像
ddepth 目标图像的所需图像深度, 通常为-1, 意思是与原图像保持一致;
图像深度是指储存每个像素点所用的位数,用来表示图像的色彩分辨率
kernel 卷积核
anchor 内核锚点,默认值为(-1,1),表示锚点位于卷积核中心
dst 卷积完成后得到的输出图像
# 读取图像
img = cv2.imread('img/CH07-2.jpg')
x = img.shape[0]
y = img.shape[1]
# 卷积核
kernel = np.ones((20,20), np.float32)/400
# 2D 卷积
dst = cv2.filter2D(img, -1, kernel)
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.1.2 平均卷积

dst = cv2.blur(src, ksize, anchor = None, borderType = None)

参数 说明
src 进行卷积的图像
ksize 元祖形式,且卷积核的长与宽必须是奇数
anchor 内核锚点,默认值为(-1,1),表示锚点位于卷积核中心
dst 卷积完成后得到的输出图像
# 读取图像
img = cv2.imread('img/CH07-2.jpg')
x = img.shape[0]
y = img.shape[1]

# 平均卷积
dst = cv2.blur(img,(11,11))
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.1.3 高斯模糊

dst = cv2.GaussianBlur(src, ksize, sigmaX, sigmaY = None)

参数 说明
src 要进行高斯模糊的图像
ksize 高斯核的形状
sigmaX 高斯函数沿X 轴方向的标准差
sigmaY 高斯函数沿 y 轴方向的标准差
dst 输出图像

sigmaY 默认和 sigmaX 保持一致,如果 sigmaX 和 sigmaY同时为 0, 函数会根据卷积核的大小自行计算出响应的值.

在指定高斯核的宽和高,两个值必须是奇数.

# 读取图像
img = cv2.imread('img/CH07-2.jpg')
x = img.shape[0]
y = img.shape[1]

# 高斯模糊
dst = cv2.GaussianBlur(img,(11,11),0)
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.1.4 中值滤波

dst = cv2.medianBlur(src, ksize)

参数 说明
src 要进行中值滤波的原图像
ksize 卷积核的大小,这里并不是元组大小, 只需要一个整数即可
dst 输出图像
# 读取图像
img = cv2.imread('img/CH07-2.jpg')
x = img.shape[0]
y = img.shape[1]

# 中值滤波,让函数自己计算相关标准差
dst = cv2.medianBlur(img, 5)
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.1.5 双边滤波

在保持图像轮廓清晰的情况下进行噪声的去除.

dst = cv2.bilateralFilter(src, sigmaColor, sigmaSpace)

参数 说明
src 进行双边滤波的原图像
d 领域直径
sigmaColor 灰度值相似性高斯函数标准差
sigmaSpace 空间高斯函数标准差
dst 输出函数

双边滤波在进行图像卷积运算的时候会同时使用空间权重和灰度值相似性权重;

灰度值相似性高斯函数用来判断周边的像素点是否与中心像素点灰度值相近,只有灰度值相似的像素点才回被用作卷积运算。

空间高斯函数用来确认像素点是否在中心点周边,只有在中心点周边的像素点才会对像素点的中心点产生影响。

# 读取图像
img = cv2.imread('img/CH07-3.jpg')
x = img.shape[0]
y = img.shape[1]
# 双边滤波实现美颜滤镜
dst = cv2.bilateralFilter(img, 11, 40, 40)
# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img', img)
cv2.imshow('img', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.1.6 滤波后的处理操作

在进行 2D 卷积和平均卷积后,图像上还有淡淡的白色印记,这时候需要滤波处理掉这些白点

# 读取图像
img = cv2.imread('img/CH07-2.jpg')
x = img.shape[0]
y = img.shape[1]

# 转换为灰度图
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 卷积核
kernel = np.ones((5,5), np.float32)/25

# 2D 卷积
dst = cv2.filter2D(grey, -1, kernel)

# 阈值操作
ret, thresh = cv2.threshold(dst, 127, 255, cv2.THRESH_BINARY)

# 图像显示
if ret:
    cv2.namedWindow('img', cv2.WINDOW_NORMAL)
    cv2.resizeWindow('img', int(y), int(x))
    cv2.imshow('img', thresh)
    cv2.imshow('imeg', dst)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
else:
    print('二值化失败!')

3. 形态学转换

形态学转换主要有两个基本操作:膨胀与腐蚀.

3.1 形态学腐蚀

腐蚀的作用是把图像中前景物体的轮廓给腐蚀掉,其余部分保持不变.卷积核会沿着图像周边滑动.

dst = cv2.erode(src, kernel, anchor = None, iterations = None)

如果与输入图像像素值对应的卷积核内部元素均为 1 , 那么该中心元素就保持为原来的像素值,否则就被赋值为 0.

除了用于去噪外,还可以用来物体的拆分.

参数 说明
src 要进行图像腐蚀的原图像
kernel 用来进行图像腐蚀的卷积核
anchor 锚点,默认为(-1, 1), 处于内核中心位置
iterations 对图像进行形态学腐蚀的次数
dst 图像腐蚀后的输出图像
# 读取图像
img = cv2.imread('img/CH07-4.jpg')
x = img.shape[0]
y = img.shape[1]

# 设置卷积核
kernel = np.ones((5,5),np.uint8)

# 颜色空间转换
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 形态学腐蚀
erode = cv2.erode(grey, kernel, iterations= 1)

# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img', erode)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.2 形态学膨胀

只要原图形中像素值对应的卷积核中存在一个元素的像素值为 1,那么其中心元素的像素值就是 1.

dst = cv2.dilate(src, kernel, anchor = None, iterations = None)

参数 说明
src 要进行图像膨胀的原图像
kernel 用来进行图像膨胀的卷积核
anchor 锚点,默认为(-1, 1), 处于内核中心位置
iterations 对图像进行形态学腐蚀的次数
dst 图像膨胀后的输出图像

假如我们想要得到没有噪声的图像,也不希望图像中的两个物体分开,可以采用先腐蚀再膨胀的操作。

# 读取图像
img = cv2.imread('img/CH07-5.jpg')
x = img.shape[0]
y = img.shape[1]

# 设置卷积核
kernel = np.ones((5,5),np.uint8)

# 颜色空间转换
grey = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 形态学腐蚀 6 次
erode = cv2.erode(grey, kernel, iterations=6)

# 形态学膨胀 6 次
dilate = cv2.dilate(erode, kernel, iterations= 6 )

# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img', dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.3 形态学高级操作

dst = cv2.morphotogyEx(src, op, kernel, anchor = None, iterations = None)

参数 说明
src 要进行图像腐蚀的原图像
op 形态学高级操作名称
kernel 执行形态学操作的卷积核
anchor 锚点,默认为(-1, 1), 处于内核中心位置
iterations 对图像进行形态学腐蚀的次数
dst 形态学操作后的输出图像

3.3.1 开运算

cv2.MORPH_OPEN : 图像先进行腐蚀再进行膨胀操作

# 读取图像
img = cv2.imread('img/CH07-5.jpg')
x = img.shape[0]
y = img.shape[1]

# 设置卷积核
kernel = np.ones((5,5), np.uint8)

# 颜色空间转换
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 开运算 1 次
opening = cv2.morphologyEx(grey, cv2.MORPH_OPEN, kernel)

# 显示图像
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img', opening)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.3.2 闭运算

cv2.MORPH_CLOSE : 图像先进行膨胀在进行腐蚀操作,与开运算相反

用来填充前景物体中的小洞,或者填充前景上的小黑点

# 读取图像
img = cv2.imread('img/CH07-6.jpg')
x = img.shape[0]
y = img.shape[1]

# 设置卷积核
kernel = np.ones((5,5),np.uint8)

# 颜色空间转换
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 进行 1 次闭运算
closing = cv2.morphologyEx(grey, cv2.MORPH_CLOSE, kernel, iterations=6)

# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img', closing)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.4 形态学梯度

cv2.MORPH_GRADIENT : 形态学梯度为形态学膨胀与腐蚀的差

得到的是噪点图像

# 读取图像
img = cv2.imread('img/CH07-4.jpg')
x = img.shape[0]
y = img.shape[1]

# 设置卷积核
kernel = np.ones((5,5), np.uint8)

# 颜色空间转换
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 获取形态学梯度
gra = cv2.morphologyEx(grey, cv2.MORPH_GRADIENT, kernel)

# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img', gra)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.5 形态学礼貌

cv2.MORPH_TOPHAT : 输入图像与进行开运算后的输出图像之间的差

# 读取图像
img = cv2.imread('img/CH07-4.jpg')
x = img.shape[0]
y = img.shape[1]

# 设置卷积核
kernel = np.ones((5, 5), np.uint8)

# 颜色空间转换
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 获取形态学梯度
gra = cv2.morphologyEx(grey, cv2.MORPH_TOPHAT, kernel)

# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img', gra)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.6 形态学黑帽

cv2.MORPH_BLACKHAT: 输入图像与进行开运算后的输出图像之间的差

# 读取图像
img = cv2.imread('img/CH07-4.jpg')
x = img.shape[0]
y = img.shape[1]

# 设置卷积核
kernel = np.ones((5, 5), np.uint8)

# 颜色空间转换
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 获取形态学梯度
gra = cv2.morphologyEx(grey, cv2.MORPH_BLACKHAT, kernel, iterations=6)

# 图像显示
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', int(y), int(x))
cv2.imshow('img', gra)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.7 结构化元素

创建卷积核

kernel = cv2.getStructuringElement(shape, ksize, anchor = None)

参数 说明
shape 卷积核形状
cv2.MORPH_RECT : 结构化长方形
cv2.MORPH_ELLIPSE: 结构化椭圆
cv2.MORPH_CROSS:结构化十字形
ksize 卷积核大小,以元祖形式传入
anchor 锚点,默认为(-1,-1), 处于内核中心位置
kernel 得到的卷积核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
print(kernel)